package com.njtoyo.taxi.admin.service.platform.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.njtoyo.taxi.admin.cache.SecondaryCachePutter;
import com.njtoyo.taxi.admin.library.Const;
import com.njtoyo.taxi.admin.mapper.secondary.entity.Resource;
import com.njtoyo.taxi.admin.mapper.secondary.entity.RoleResourceMapping;
import com.njtoyo.taxi.admin.mapper.secondary.mapper.AdminUserMapper;
import com.njtoyo.taxi.admin.mapper.secondary.mapper.ResourceMapper;
import com.njtoyo.taxi.admin.mapper.secondary.mapper.RoleResourceMappingMapper;
import com.njtoyo.taxi.admin.rest.wrapper.platform.resource.ResourceCreateWrapper;
import com.njtoyo.taxi.admin.rest.wrapper.platform.resource.ResourceUpdateSortWrapper;
import com.njtoyo.taxi.admin.rest.wrapper.platform.resource.ResourceUpdateWrapper;
import com.njtoyo.taxi.admin.service.platform.ResourceService;
import com.njtoyo.taxi.admin.library.common.util.CopyUtil;
import com.taxi.entity.common.RestResult;
import com.taxi.entity.common.ResultEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Service
@DS(Const.SECONDARY_DS)
public class ResourceServiceImpl implements ResourceService {

    @Autowired
    private ResourceMapper resourceMapper;

    @Autowired
    private RoleResourceMappingMapper roleResourceMappingMapper;

    @Autowired
    private SecondaryCachePutter secondaryCachePutter;

    @Autowired
    private AdminUserMapper adminUserMapper;


    @Override
    public RestResult getList() {
        QueryWrapper<Resource> wrapper = new QueryWrapper<>();
        wrapper.orderByAsc("sort");

        List<Resource> data = resourceMapper.selectList(wrapper);

        //定义新的list
        List<Resource> resourceList = new ArrayList<>();

        //先找到所有的一级分类
        for (Resource item : data) {
            // 一级菜单的parentId是0
            if (item.getParentId() == 0) {
                resourceList.add(item);
            }
        }

        // 为一级菜单设置子菜单，getChild是递归调用的
        for (Resource item : resourceList) {
            item.setChildren(getChilde(item.getId(), data));
        }

        return RestResult.success(resourceList);
    }

    /**
     * 递归查找子菜单
     *
     * @param id       当前菜单id
     * @param rootList 要查找的列表
     * @return
     */
    private List<Resource> getChilde(Long id, List<Resource> rootList) {
        //子菜单
        List<Resource> childList = new ArrayList<>();
        for (Resource resource : rootList) {
            // 遍历所有节点，将父菜单id与传过来的id比较
            if (resource.getParentId().equals(id)) {
                childList.add(resource);
            }
        }
        // 把子菜单的子菜单再循环一遍
        for (Resource resource : childList) {
            resource.setChildren(getChilde(resource.getId(), rootList));
        }
        // 递归退出条件
        if (childList.size() == 0) {
            return null;
        }
        return childList;
    }

    @Override
    public RestResult createResource(ResourceCreateWrapper createWrapper) {
        Resource resource = CopyUtil.copy(createWrapper, Resource.class);

        int res = resourceMapper.insert(resource);

        return RestResult.success(res);
    }

    @Override
    public RestResult updateResource(Long id, ResourceUpdateWrapper request) {
        // 校验资源是否存在
        Resource resource = resourceMapper.selectById(id);
        if (resource == null) {
            return RestResult.build(ResultEnum.NOT_FOUND);
        }

        Resource updateData = CopyUtil.copy(request, Resource.class);
        updateData.setId(id);

        // 修改权限资源
        resourceMapper.updateById(updateData);

        // 删除用户缓存
        deleteAdminUserCacheByResourceId(id);

        return RestResult.success();
    }

    @Override
    @Transactional
    public RestResult updateResourceSort(Long parentId, ResourceUpdateSortWrapper request) {
        // 校验父级资源是否存在
        if (!parentId.equals(0L) && Objects.isNull(resourceMapper.selectById(parentId))) {
            return RestResult.build(ResultEnum.NOT_FOUND);
        }

        List<Long> reqResourceIds = request.getResourceIds();

        // 批量修改
        int num = reqResourceIds.size();
        for (int i = 0; i < num; i++) {
            resourceMapper.updateSortById(parentId, reqResourceIds.get(i), i);
        }

        return RestResult.success();
    }

    @Override
    @Transactional
    public RestResult deleteResource(Long id) {
        // 校验资源是否存在
        Resource resource = resourceMapper.selectById(id);
        if (resource == null) {
            return RestResult.build(ResultEnum.NOT_FOUND);
        }

        // 校验是否存在下级
        Integer children = resourceMapper.selectCount(new QueryWrapper<Resource>().eq("parent_id", id));
        if (children > 0) {
            return RestResult.failed("当前权限资源存在下级，不可被删除");
        }

        // 校验资源是否已被使用
        List<RoleResourceMapping> roleResourceMappings = getRoleResourceMappingByResourceId(id);

        if (roleResourceMappings.size() > 0) {
            return RestResult.failed("当前权限资源已被使用，不可被删除");
        }

        // 删除权限资源
        resourceMapper.deleteById(id);

        // 删除用户缓存
        deleteAdminUserCacheByResourceId(id);

        return RestResult.success();
    }

    /**
     * 根据资源id获取被使用的role的列表
     *
     * @param id
     * @return
     */
    private List<RoleResourceMapping> getRoleResourceMappingByResourceId(Long id) {
        QueryWrapper<RoleResourceMapping> wrapper = new QueryWrapper<>();
        wrapper.eq("resource_id", id);

        return roleResourceMappingMapper.selectList(wrapper);
    }

    /**
     * 根据资源id删除管理员用户的cache
     *
     * @param id
     * @return
     */
    private void deleteAdminUserCacheByResourceId(Long id) {
        // 根据权限id获取管理员用户ids
        List<Long> adminUserIds = adminUserMapper.getAdminUserIdsByResourceId(id);

        if (CollUtil.isNotEmpty(adminUserIds)) {
            secondaryCachePutter.deleteAdminUserCache(adminUserIds);
        }
    }
}
